import {
  AfterViewInit,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef,
  EventEmitter,
  forwardRef,
  Input,
  OnChanges,
  OnDestroy,
  OnInit,
  Output,
  Renderer2,
  SimpleChanges,
  TemplateRef,
  ViewChild,
  ViewContainerRef,
  ViewEncapsulation,
} from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal';
import { fromEvent, Subject } from 'rxjs';
import { distinctUntilChanged, filter, takeUntil, tap } from 'rxjs/operators';
import { merge as _merge } from 'lodash';
import { StandardDate } from '../core/calendar-base/standard-date';
import { CalendarBaseComponent } from '../core/calendar-base/calendar-base.component';
import { DateService, I18NService, InputBoolean, LvCalendarEvents, LvCalendarMode, OverlayService } from '../core/api';
import { LvConfig } from '../core/config';

@Component({
  selector: 'lv-calendar',
  templateUrl: './calendar.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef((): typeof CalendarComponent => CalendarComponent),
      multi: true,
    },
  ],
  host: {
    '[class.lv-calendar]': 'true',
  },
})
export class CalendarComponent extends CalendarBaseComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
  @Input() @InputBoolean() lvResize = false; // 是否可以调整日历行高宽度

  @Input() lvCalendarEvents: LvCalendarEvents[];

  @Input() lvCalendarMode: LvCalendarMode = 'month';

  @Input() @InputBoolean() lvOnlyShowActiveCell = false; // 是否显示上一月、下一月的单元格

  @Output() lvActiveDateChange = new EventEmitter<any>();

  @Input() @InputBoolean() lvCalendarTitleReadonly = true;

  @Input() lvCalendarCell: TemplateRef<Date> | null = null; // 自定义日历单元格

  @Input() lvCalendarEventCell: TemplateRef<any> | null = null;

  @Input() lvCalendarHeaderLeft: TemplateRef<Date> | null = null; // 自定义日历头部左侧内容

  @Input() lvCalendarHeaderRight: TemplateRef<Date> | null = null; // 自定义日历头部右侧内容

  @ViewChild('calendarPanle', { static: false }) calendarPanle: TemplateRef<any>;

  @Input() lvTimezoneOffset: number = LvConfig.datePickerOptions.lvTimezoneOffset; // 本地时间与格林威治标准时间 (GMT) 的分钟差

  @Output() lvCalendarModeChange: EventEmitter<'month' | 'year'> = new EventEmitter();

  @ViewChild('cellBody', { read: ElementRef, static: false }) cellBodyRef: ElementRef;

  @ViewChild('resizeMark', { read: ElementRef, static: false }) resizeMarkRef: ElementRef;

  @ViewChild('resizeLine', { read: ElementRef, static: false }) resizeLineRef: ElementRef;

  overlayRef;
  activeDateDay;
  activeDateYear;
  eventRows = [];
  activeDateMonth;
  open: boolean = false;
  isChrome: boolean = false;

  language = LvConfig.language;
  currentMode: LvCalendarMode = 'month';

  private _endY;

  private _target;

  private _startY;

  private _offsetY;

  private _cellBody;

  private _startFlag;
  private _activeHeight;
  // resize
  private _activeElement;
  private _resizeHelpLine;
  private _resizeHelpMark;
  private _destroy$ = new Subject<void>();
  private _open$ = new Subject<boolean>();

  constructor(
    public cdr: ChangeDetectorRef,
    public dateService: DateService,
    public i18n: I18NService,
    public elementRef: ElementRef,
    private _overlayService: OverlayService,
    private _overlay: Overlay,
    private _viewContainerRef: ViewContainerRef,
    private _renderer: Renderer2,
  ) {
    super(cdr, dateService);
    this.prefixCls = 'lv-calendar';
  }

  /**
   * 判断单元格中当前索引位置是否被占用，若被占用则索引++
   * @param arr 单元格已使用位置数组
   * @param index 需判断的位置索引
   * @returns 返回未被占用的位置索引值
   */
  cellPosIndexInclude = (arr, index): any => {
    let idx = index;
    if (!arr.includes(idx)) {
      return idx;
    }
    idx++;
    return this.cellPosIndexInclude(arr, idx);
  };

  /**
   * 计算天数差
   * @param startDate 开始日期
   * @param endDate 结束日期
   */
  getDiffInDay = (startDate, endDate): number => {
    if (!startDate || !endDate) {
      return 0;
    }

    // 需要把日期的时、分、秒置为0，计算出来的日期差才准确
    return Math.ceil((endDate.setHours(0, 0, 0, 0) - startDate.setHours(0, 0, 0, 0)) / (1000 * 60 * 60 * 24));
  };

  /**
   * 是否是同一天或同一月
   * @param source 源日期
   * @param target 目标日期
   * @param mode 当前日历模式
   */
  compareDate = (source, target, mode: LvCalendarMode): boolean => {
    if (!source || !target) {
      return false;
    }
    if (mode === 'month') {
      return new StandardDate(source).isSameDay(new StandardDate(target));
    } else {
      return new StandardDate(source).isSameMonth(new StandardDate(target));
    }
  };

  /**
   * 设置每个事件的渲染数据
   * @param mode 日历模式
   * @param row 行
   * @param cell 单元格
   * @param index 在单元格中的位置索引
   * @param width 宽度
   * @param event 事件
   * @returns renderData
   */
  setEventRenderData = (mode: LvCalendarMode, row, cell, index, width, event): any => {
    const renderData = _merge(
      {},
      {
        row,
        cell,
        title: event.title,
        top: index * 26,
        left: mode === 'month' ? cell * (100 / 7) : cell * (100 / 3),
        width,
        cellPosIndex: index,
        originData: event,
      },
    );
    return renderData;
  };

  /**
   * 查找、设置事件在单元格中的位置
   * 判断时间是否已经存在于temps中
   * 1、存在则计算当前事件在单元格中的位置并存入记录中
   * 2、不存在则将时间以及新占用的第一个位置信息存入记录中
   * 每次查找被占用位置均从第一位开始查找，避免出现大面积空白区域。如当前单元格的第3个位置已被占用（结束时间使用），第1、2个位置未被使用，则优先使用第1个位置
   * @param source 单元格位置信息数据
   * @param target 事件时间，被判断时间
   * @param mode 日历模式
   * @param usedIndex 当前被使用的位置索引
   * @param value 单元格日期
   * @param flag 当前单元格位置信息是否有数据
   * @param isEnd 是否是事件结束时间
   * @returns 被判断事件时间所在位置索引
   */
  setCellEventPos = (source, target, mode, usedIndex, value, flag, isEnd = false): any => {
    let index = usedIndex;
    let dataFlag = flag;
    source.forEach((item): void => {
      if (!item.date) {
        return;
      }
      if (this.compareDate(item.date, target, mode)) {
        const _cacheIndex = 0;
        if (!index) {
          index = this.cellPosIndexInclude(item.used, _cacheIndex);
        }

        item.used.push(index);
        dataFlag = true;
      }
    });

    if (!dataFlag) {
      if (!isEnd) {
        index = 0;
      }
      source.push({ date: value, used: [index] });
    }

    return index;
  };

  trackByIndex(index): any {
    return index;
  }

  registerOnChange(fn: any): void {
    super.registerOnChange(fn);
  }

  registerOnTouched(fn: any): void {
    super.registerOnTouched(fn);
  }

  cellMouseLeave(): void {
    this.lvCellMouseLeave.emit(this.value);
  }

  ngOnDestroy(): void {
    this._destroy$.next();
    this._destroy$.complete();

    this.close();
  }

  toggleOpen(): void {
    if (!this.lvCalendarTitleReadonly) {
      this._open$.next((this.open = !this.open));
    }
  }

  /**
   * 选中日期变更
   */
  selectDateChange(value): void {
    this.valueChange.emit(value);
    this._onChange(value.localDate);
  }

  /**
   * 关闭下拉
   */
  close(): void {
    if (this.overlayRef?.overlayRef.hasAttached()) {
      this.overlayRef.close();
    }
  }

  ngOnInit(): void {
    this.currentMode = this.lvCalendarMode;
    this.prefixCls = this.currentMode === 'month' ? 'lv-calendar' : 'lv-calendar-month';
    this._subOpen();
  }

  /**
   * 转化日期为标准的StandardDate
   * @param date 输入日期
   */
  converDate(date): StandardDate {
    if (date === null || date === undefined) {
      return new StandardDate(new Date());
    } else {
      return new StandardDate(date);
    }
  }

  /**
   * 渲染日历视图
   */
  renderCalendarUI(): void {
    this.renderCalendarHeader();
    this.renderCalendar({ showDatePanel: this.currentMode === 'month', showMonthPanel: this.currentMode === 'year' });
    this.cdr.markForCheck();
  }

  /**
   * 根据时区设置正确日期
   * @param value 输入日期
   */
  setValue(value): void {
    const offsetDate = this.lvTimezoneOffset
      ? this.dateService.getTimezoneOffsetDate(value, this.lvTimezoneOffset, true)
      : value;
    this.value = this.converDate(offsetDate);

    this.renderCalendarUI();
  }

  /**
   * 判断当前日期是否是不可用状态
   * @param value 输入日期
   */
  checkDateDisableStatus(value): boolean {
    let isDateDisabled = false;
    const date = value ? new StandardDate(value) : null;

    if (this.lvDisabledDate) {
      isDateDisabled = this.lvDisabledDate(date.localDate);
    }
    return !date || isDateDisabled;
  }

  /**
   * 切换模式
   */
  modeChange(mode): void {
    this.currentMode = mode;
    this.lvCalendarMode = mode;
    this.prefixCls = mode === 'month' ? 'lv-calendar' : 'lv-calendar-month';
    this.renderCalendarUI();
    mode === 'month' ? this.renderMonthEvents() : this.renderYearEvents();
    this.lvCalendarModeChange.emit(mode);
  }

  /**
   * 渲染日历头部
   */
  renderCalendarHeader(): void {
    const date = this.activeDate;
    this.activeDateYear = this.dateService.format(date.localDate, 'yyyy');
    this.activeDateMonth = this.dateService.format(date.localDate, this.language === 'en-us' ? 'MMM' : 'M');
    this.activeDateDay = this.dateService.format(date.localDate, 'd');
  }

  /**
   * 订阅切换面板的流
   */
  _subOpen(): void {
    this._open$
      .pipe(
        tap((res: boolean): void => {
          if (!res) {
            this.close();
          }
        }), // 关闭
        filter((res): any => res), // 打开
        takeUntil(this._destroy$),
      )
      .subscribe((): void => {
        this._openPanelOverlay();
      });
  }

  writeValue(value: any): void {
    if (value instanceof Date) {
      if (this.checkDateDisableStatus(value)) {
        // eslint-disable-next-line no-console
        console.error('Calendar component initialization value is disabled.');
      } else {
        this.setValue(value);
      }
    } else if (value === null) {
      this.setValue(null);
    } else if (value) {
      // eslint-disable-next-line no-console
      console.error('The format of date is incorrect.');
    } else {
      return;
    }
  }

  doSelect(value, isNow = false): void {
    if (this.currentMode === 'month') {
      if (!this.value && !isNow) {
        this.value = new StandardDate(
          new StandardDate(
            new StandardDate(new StandardDate(value.setHours(0)).setMinutes(0)).setSeconds(0),
          ).setMilliseconds(0),
        );
      } else {
        this.value = value;
      }
    } else {
      this.value = new StandardDate(value);
    }

    this.selectDateChange(this.value);
    this.renderCalendarUI();
  }

  ngOnChanges(changes: SimpleChanges): void {
    const { lvCalendarMode, lvCalendarEvents } = changes;

    if (lvCalendarMode) {
      this.currentMode = lvCalendarMode.currentValue;
      this.prefixCls = this.currentMode === 'month' ? 'lv-calendar' : 'lv-calendar-month';
      if (this.activeDate) {
        this.renderCalendarUI();
      }
      this.currentMode === 'month' ? this.renderMonthEvents() : this.renderYearEvents();
    }

    if (lvCalendarEvents) {
      this.currentMode === 'month' ? this.renderMonthEvents() : this.renderYearEvents();
    }
  }

  /**
   * 切换年、月
   * @param param 改变的日期或者改变的数量。changeMode为button时，只能传数量
   * @param type 改变类型，年、月
   * @param changeMode 切换方式，通过按button点击切换或者通过picker选择切换
   */
  changeDate(param, type: 'year' | 'month', changeMode: 'button' | 'picker' = 'button'): void {
    if (changeMode === 'picker') {
      this.activeDate = new StandardDate(param.value);
    } else {
      this.activeDate =
        type === 'year'
          ? new StandardDate(this.activeDate.addYears(param))
          : new StandardDate(this.activeDate.addMonths(param));
    }

    this.renderCalendarUI();
    this.currentMode === 'month' ? this.renderMonthEvents() : this.renderYearEvents();
    this.lvActiveDateChange.emit({ value: this.activeDate });
  }

  /**
   * 选中日期
   * @param cell 当前单元格
   */
  selectCalendarCell(cell): void {
    if (cell.isDisabled) {
      return;
    }

    if (this.currentMode === 'month') {
      if (this.value) {
        let newDate: Date;
        newDate = this.value.setYear(cell.value.getFullYear());
        newDate = this.value.setMonth(cell.value.getMonth());
        newDate = this.value.setDate(cell.value.getDate());
        this.doSelect(new StandardDate(newDate));
      } else {
        this.doSelect(new StandardDate(cell.value));
      }
      this.renderMonthEvents();
    } else {
      this.doSelect(cell.value);
      this.renderYearEvents();
    }
  }

  /**
   * 调整日历单元格高度,改变当前行高
   * 2. mousemove: 更新辅助线位置
   */
  resize(target): void {
    fromEvent(target, 'mousemove')
      .pipe(
        filter(() => this._startFlag),
        distinctUntilChanged(),
        takeUntil(this._destroy$),
      )
      .subscribe((res: any): void => {
        this._endY = res.clientY;
        this._offsetY = this._endY - this._startY;
        if (this._activeHeight + this._offsetY <= 58) {
          return;
        }
        // 辅助线的位置为当前开始位置减去日历主体在页面中的top值
        const clientY = this._cellBody.getBoundingClientRect().top;
        this._renderer.setStyle(this._resizeHelpLine, 'top', `${this._endY - clientY}px`);
      });
  }

  /**
   * 调整日历单元格高度,改变当前行高
   * 3. mouseup: 清除,更新当前行高
   */
  confirmResize(target): void {
    fromEvent(target, 'mouseup')
      .pipe(
        filter(() => this._startFlag),
        takeUntil(this._destroy$),
      )
      .subscribe((res: MouseEvent): void => {
        this._startFlag = false;
        this._endY = res.clientY;
        this._offsetY = this._endY - this._startY;

        // mouseup时，无论拖拽后宽度是否变更，都已完成拖拽操作，样式都需要变更
        this._renderer.removeClass(target, 'lv-user-select-disabled');
        this._renderer.addClass(this._resizeHelpMark, 'lv-display-none');
        this._renderer.addClass(this._resizeHelpLine, 'lv-display-none');

        if (this._activeHeight + this._offsetY <= 58) {
          return;
        }

        this._activeElement.style.height = `${this._activeHeight + this._offsetY}px`;
      });
  }

  /**
   * 调整日历单元格高度,改变当前行高
   * 1. mousedown: 记录当前行高度
   */
  activeResize(event): void {
    if (!this.lvResize) {
      return;
    }
    event.stopPropagation();
    event.preventDefault();
    this._activeElement = event.target.offsetParent;
    this._startFlag = true;

    const bodyElement = document.body;

    this._activeHeight = this._activeElement.clientHeight;
    this._startY = event.clientY;
    // 阻止文本选中导致不触发mouseup
    this._renderer.addClass(bodyElement, 'lv-user-select-disabled');
    this._renderer.removeClass(this._resizeHelpMark, 'lv-display-none');
    this._renderer.removeClass(this._resizeHelpLine, 'lv-display-none');
    // 辅助线的位置为当前开始位置减去日历主体在页面中的top值
    const clientY = this._cellBody.getBoundingClientRect().top;
    this._renderer.setStyle(this._resizeHelpLine, 'top', `${this._startY - clientY}px`);
  }

  ngAfterViewInit(): void {
    // 解决有滚动条时样式错误， NEED_DO：IE和火狐下需监听是否出现滚动条，减去滚动条宽度
    const explorer = window.navigator.userAgent;
    this.isChrome = explorer.indexOf('Chrome') >= 0 && explorer.indexOf('Edge') === -1;

    this.currentMode === 'month' ? this.renderMonthEvents() : this.renderYearEvents();
    this._target = this.elementRef.nativeElement.querySelector('.lv-canlendar-header-center .center');

    // NEED_DO: 目前布局不支持年模式
    if (this.lvResize) {
      if (this.currentMode === 'month') {
        this._cellBody = this.cellBodyRef?.nativeElement;
      }
      this._resizeHelpLine = this.resizeLineRef.nativeElement;
      this._resizeHelpMark = this.resizeMarkRef.nativeElement;

      const bodyElement = document.body;
      this.resize(bodyElement);
      this.confirmResize(bodyElement);
    }
  }

  /**
   * 打开下拉panel overlay
   */
  _openPanelOverlay(): void {
    if (!this.overlayRef?.overlayRef.hasAttached()) {
      const config = new OverlayConfig({
        hasBackdrop: false,
        scrollStrategy: this._overlay.scrollStrategies.block(),
        width: this.lvCalendarMode === 'month' ? 140 : 70,
        positionStrategy: this._overlay
          .position()
          .flexibleConnectedTo(this._target)
          .withPositions([
            {
              originX: 'center',
              originY: 'bottom',
              overlayX: 'center',
              overlayY: 'top',
            },
            {
              originX: 'center',
              originY: 'top',
              overlayX: 'center',
              overlayY: 'bottom',
            },
          ]),
      });
      const extendConfig = {
        afterClose: (): void => {
          this.open = false;
        },
      };

      const portal = new TemplatePortal(this.calendarPanle, this._viewContainerRef);
      this.overlayRef = this._overlayService.open(portal, config, extendConfig);
    }
  }

  setEventRows(index: number, item: any): void {
    this.eventRows.forEach((event, i): void => {
      if (i === index) {
        event.eventItems.push(item);
      }
    });
  }

  /**
   * 渲染年模式事件视图
   */
  renderYearEvents(): void {
    this.eventRows = [{ eventItems: [] }, { eventItems: [] }, { eventItems: [] }, { eventItems: [] }];
    const _temps = []; // 用于存储有事件的单元格以及单元格中事件的位置

    // 生成事件renderData
    this.C_months.forEach((m): void => {
      this.handleMonth(m, _temps);
    });
  }

  handleMonth(m: any, _temps: any[]): void {
    const _row = Math.floor(new StandardDate(m.value).getMonth() / 3);
    const _cell = new StandardDate(m.value).getMonth() % 3;

    // 使用日历单元格匹配事件的日期，计算出每一个单元格中的事件
    this.lvCalendarEvents.forEach((e: LvCalendarEvents): void => {
      this.handleCalendarEvents(e, m, _temps, _row, _cell);
    });
  }

  handleCalendarEvents(e: LvCalendarEvents, m: any, _temps: any[], _row: number, _cell: number): void {
    if (!e.startDate) {
      throw new Error('startDate is not defined in event');
    }

    // 匹配开始日期是否相等
    if (!this.compareDate(m.value, e.startDate, 'year')) {
      return;
    }

    let eventUsedIndex: number;

    // 查找、设置事件在单元格中的位置
    eventUsedIndex = this.setCellEventPos(_temps, e.startDate, 'year', eventUsedIndex, m.value, false);

    const _width = (e.endDate ? e.endDate.getMonth() - e.startDate.getMonth() + 1 : 1) * (100 / 3);
    const eventItem = this.setEventRenderData('year', _row, _cell, eventUsedIndex, _width, e);
    this.setEventRows(_row, eventItem);

    // 若开始时间与结束时间为同一天，则无需进行计算
    if (!e.endDate || this.compareDate(e.endDate, e.startDate, 'year')) {
      return;
    } else {
      // 判断是否为结束时间,若不是则继续查找下一个单元格是否为endDate，直到找到为止。
      let nextCell = (new StandardDate(e.startDate).getMonth() % 3) + 1;
      let endRow = _row;

      // 设置换行event的数据
      // NEED_DO:换行后nextcell为0，以此做判断
      const setBreakEventData = (row: number, cell: number, used: number): void => {
        if (cell === 0) {
          const _bankEventWidth = (e.endDate ? e.endDate.getMonth() - e.startDate.getMonth() : 1) * (100 / 3);
          const _bankEventItem = this.setEventRenderData('year', row, cell, used, _bankEventWidth, e);
          this.setEventRows(row, _bankEventItem);
        }
      };

      const setEndTemp = (): void => {
        const nextIndex = 3 * endRow + nextCell;

        // 若当前行的所有单元格均没有endDate，则换行继续查找，并将endDate之前的单元格都记录下来，并放入eventRowData中
        if (nextCell === 3) {
          nextCell = 0;
          endRow++;
          eventUsedIndex = 0;
        }

        const cellValue = this.C_months[nextIndex]?.value;

        if (this.compareDate(cellValue, e.endDate, 'year')) {
          // 查找、设置事件在单元格中的位置
          eventUsedIndex = this.setCellEventPos(_temps, e.endDate, 'year', eventUsedIndex, cellValue, false, true);

          setBreakEventData(endRow, nextCell, eventUsedIndex);
        } else {
          // 查找、设置事件在单元格中的位置
          eventUsedIndex = this.setCellEventPos(_temps, e.endDate, 'year', eventUsedIndex, cellValue, false, true);

          setBreakEventData(endRow, nextCell, eventUsedIndex);

          nextCell++;
          setEndTemp();
        }
      };

      setEndTemp();
    }
  }

  /**
   * 渲染月模式事件视图
   * 按日历单元格日期顺序去遍历，查找事件中开始日期与当前单元格日期一致，则计算当前事件在单元格的位置
   * 再判断是否有结束日期，若有则找到结束日期的单元格，事件在单元格中的位置为开始日期的位置
   */
  renderMonthEvents(): void {
    this.eventRows = [];
    const _temps = []; // 用于存储单元格中事件的位置信息，以位置索引为标识，若单元格没有事件，则不记录
    // 每行数据，日历月模式固定6行
    const validRowIndexes = [0, 1, 2, 3, 4, 5];
    const _eventRows = [[], [], [], [], [], []];

    // 设置事件行数据
    const setEventRowData = (index: number, item: object): void => {
      if (validRowIndexes.includes(index)) {
        _eventRows[String(index)].push(item);
      }
    };

    // 生成事件renderData
    this.C_rows.forEach((r, i): void => {
      this.handleRowCells(r, i, _temps, setEventRowData);

      if (validRowIndexes.includes(i)) {
        this.eventRows.push({ eventItems: _eventRows[i] });
      }
    });
  }

  handleRowCells(r: any, _row: number, _temps: any[], setEventRowData: { (index: any, item: object): void }): void {
    r.cells.forEach((c, j): void => {
      const _cell = j;

      // 使用日历单元格匹配事件的日期，计算出每一个单元格中的事件
      this.lvCalendarEvents.forEach((e): void => {
        if (!e.startDate) {
          throw new Error('startDate is not defined in event');
        }
        if (!this.compareDate(c.value, e.startDate, 'month')) {
          return;
        }
        // 匹配开始日期是否相等
        // 查找、设置事件在单元格中的位置
        let eventUsedIndex = this.setCellEventPos(_temps, e.startDate, 'month', 0, c.value, false);

        const tempWidth =
          e.endDate && !this.compareDate(e.endDate, e.startDate, 'month')
            ? this.getDiffInDay(e.startDate, e.endDate) + 1
            : 1;
        const _width = tempWidth * (100 / 7);
        const eventItem = this.setEventRenderData('month', _row, _cell, eventUsedIndex, _width, e);
        setEventRowData(_row, eventItem);

        // 若开始时间与结束时间为同一天，则无需进行计算
        if (!e.endDate || this.compareDate(e.endDate, e.startDate, 'month')) {
          return;
        }

        // 判断是否为结束时间,若不是则继续查找下一个单元格是否为endDate，直到找到为止。
        let nextCell = _cell + 1;
        let endRow = _row;

        // 设置换行event的数据
        // NEED_DO:换行后nextcell为0，以此做判断
        const setBreakEventData = (row: number, cell: number, used: any): void => {
          if (cell === 0) {
            const _bankEventWidth = (this.getDiffInDay(this.C_rows[row]?.cells[0]?.value, e.endDate) + 1) * (100 / 7);
            const _bankEventItem = this.setEventRenderData('month', row, cell, used, _bankEventWidth, e);
            setEventRowData(row, _bankEventItem);
          }
        };

        const setEndTemp = (): void => {
          // 若当前行的所有单元格均没有endDate，则换行继续查找，并将endDate之前的单元格都记录下来，并放入eventRowData中
          if (nextCell === r.cells.length) {
            nextCell = 0;
            endRow++;
            eventUsedIndex = 0;
          }

          const cellValue = this.C_rows[endRow]?.cells[nextCell]?.value;

          if (this.compareDate(cellValue, e.endDate, 'month')) {
            // 查找、设置事件在单元格中的位置
            eventUsedIndex = this.setCellEventPos(_temps, e.endDate, 'month', eventUsedIndex, cellValue, false, true);

            setBreakEventData(endRow, nextCell, eventUsedIndex);
          } else {
            // 查找、设置事件在单元格中的位置
            eventUsedIndex = this.setCellEventPos(_temps, cellValue, 'month', eventUsedIndex, cellValue, false, true);

            setBreakEventData(endRow, nextCell, eventUsedIndex);

            nextCell++;
            setEndTemp();
          }
        };

        setEndTemp();
      });
    });
  }
}
